package framework;

/**
 * Represents board that the automaton runs on
 * 
 * @author jtumarki, ntibrewa, shuaihan, wesleyk
 * 
 */
public class Board {

	// board represented as 2-d array of States
	private State[][] board;

	// width of board
	private int width;

	// height of board
	private int height;

	/**
	 * Constructor for board requires width/height and initial state
	 * 
	 * @param width
	 *            width of board
	 * @param height
	 *            height of board
	 * @param initialState
	 *            default state for board
	 */
	public Board(int width, int height, State[][] initial) {

		if (!(isLegalBoard(width, height, initial)))
			throw new IllegalArgumentException(
					"Error! The initial board is illegal");
		this.board = initial;
		this.width = width;
		this.height = height;
	}

	/**
	 * This function checks if the given board arguments construct a legal
	 * board. It essentially performs sanity checks for the arguments necessary
	 * to build a board.
	 * 
	 * @param wid
	 *            width of the board
	 * @param hei
	 *            height of the board
	 * @param initial
	 *            the 2D array the board will represent
	 * @return
	 */
	private boolean isLegalBoard(int wid, int hei, State[][] initial) {
		if (initial == null)
			return false;
		if (wid < 0 || hei < 0)
			return false;

		int h = initial.length;

		State[] row = null;
		State cur = null;

		if (h != hei)
			return false;

		for (int i = 0; i < hei; i++) {
			row = initial[i];
			if (row == null || row.length != wid) {
				return false;
			}
			for (int j = 0; j < wid; j++) {
				cur = row[j];
				if (cur == null) {
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * Get width of board
	 * 
	 * @return width of board
	 */
	public int getWidth() {
		return width;
	}

	/**
	 * Get height of board
	 * 
	 * @return height of board
	 */
	public int getHeight() {
		return height;
	}

	/**
	 * Return state given position of board
	 * 
	 * @param xPos
	 *            x position of board
	 * @param yPos
	 *            y position of board
	 * @return state at given position on board
	 */
	public State getState(int xPos, int yPos) {
		if (!isValidPosition(xPos, yPos)) {
			throw new IllegalArgumentException(
					"Error! State requested was out of board!");
		}
		return board[xPos][yPos];
	}

	/**
	 * Set state given position of board and state
	 * 
	 * @param newState
	 *            state to be set
	 * @param xPos
	 *            x position of board
	 * @param yPos
	 *            y position of board
	 */
	public void setState(State newState, int xPos, int yPos) {
		if (newState == null) {
			throw new IllegalArgumentException("Error! State cannot be null!");
		}

		if (!isValidPosition(xPos, yPos)) {
			throw new IllegalArgumentException(
					"Error! x and y coordinates are invalid!");
		}
		board[xPos][yPos] = newState;
	}

	/**
	 * Checks if position is valid
	 * 
	 * @param xPos
	 *            x position of board
	 * @param yPos
	 *            y position of board
	 * @return true if valid, false if not
	 */
	public boolean isValidPosition(int xPos, int yPos) {
		return (0 <= xPos && xPos < height && 0 <= yPos && yPos < width);
	}

}
